//
//  CCDelay.swift
//  CCFoundation_Swift
//
//  Created by zjh on 2021/11/18.
//

import UIKit
//延迟执行方法，可撤销执行的对象
public final class CCDelay: NSObject {
    
    private weak var target: NSObjectProtocol?
    
    private var sel: Selector?
    
    private var delay: TimeInterval = 0
    
    private var timer: Timer?
    
    private var count: Int = 0
    
    private let semaphore = DispatchSemaphore(value: 1)
    
    private var running = false
    
    public required init(target: NSObjectProtocol?, sel: Selector?, afterDelay delay: TimeInterval) {
        super.init()
        self.target = target
        self.sel = sel
        self.delay = delay
        
    }
    
    /// 开始执行延迟
    public func start() {
        guard target?.responds(to: sel) == true else {
            return
        }
        self.destroyTimer()
        if (!self.running) {
            self.running = true
            self.count = 1;
            self.semaphore.wait()
            CCDelay.startThread()   ///每次初始化线程引用计数器+1
            if let thread = CCDelay.delayThread {
                self.perform(#selector(createTimer), on: thread, with: nil, waitUntilDone: false)
            }
        }
    }
    
    /// 撤销延迟执行
    public func end() {
        self.destroyTimer()
    }
    
    @objc func createTimer() {
        defer { self.semaphore.signal() }   ///return之前执行解锁
        self.timer = Timer.init(timeInterval: self.delay, repeats: true, block: { [weak self] _ in
            if let self = self {
                self.delayAction()
            }
        })
        RunLoop.current.add(self.timer!, forMode: .default)
        self.timer?.fire()
        debugPrint("❤️❤️❤️创建延时执行❤️❤️❤️")
    }
    
    @objc func delayAction() {
        guard target?.responds(to: sel) == true else {
            self.destroyTimer()
            return
        }
        
        if self.count == 0 {
            debugPrint("❤️❤️❤️执行延时方法❤️❤️❤️")
            self.target?.perform(self.sel)
            self.destroyTimer()
        }
        
        self.count = self.count - 1;
    }
    
    public func destroyTimer() {
        semaphore.wait(); defer { semaphore.signal() }
        if (self.running) {
            self.running = false
            if self.timer != nil {
                debugPrint("❤️❤️❤️销毁延时执行❤️❤️❤️")
                self.timer?.invalidate()
                self.timer = nil
            }
            CCDelay.stopthread()    ///每次释放导致线程引用计数-1
        }
    }
    
    deinit {
        debugPrint("❤️❤️❤️内存释放:",type(of: self).description().components(separatedBy: ".").last!)
        self.destroyTimer()
    }
    
    static var delayThread: Thread?
    static var threadRetaincount = 0
    static let delaySemaphore = DispatchSemaphore.init(value: 1)
    
    /// 创建线程添加引用计数+1
    class func startThread() {
        self.delaySemaphore.wait()
        debugPrint("❤️❤️❤️尝试开启线程❤️❤️❤️")
        threadRetaincount += 1
        if threadRetaincount == 1 {
            delayThread = Thread.init(target: self, selector: #selector(delayThreadAction), object: nil)
            delayThread?.start()
            debugPrint("❤️❤️❤️开启线程❤️❤️❤️")
        }
        self.delaySemaphore.signal()
    }
    
    
    /// 引用计数-1，引用计数为0注销常驻线程
    class func stopthread() {
        debugPrint("❤️❤️❤️尝试关闭线程❤️❤️❤️")
        self.delaySemaphore.wait()
        if threadRetaincount == 0 {
            self.delaySemaphore.signal()
            return
        }
        threadRetaincount -= 1
        if threadRetaincount == 0 {
            delayThread?.cancel()
            debugPrint("❤️❤️❤️关闭线程❤️❤️❤️")
            delayThread = nil
        }
        self.delaySemaphore.signal()
    }
    
    @objc class func ignore() {
        debugPrint("ignore运行了")
    }
    
    @objc class func delayThreadAction() {
        Timer.scheduledTimer(timeInterval: Date.distantFuture.timeIntervalSinceNow, target: self, selector: #selector(ignore), userInfo: nil, repeats: true)
        let currentThread = Thread.current
        let currentRunloop = RunLoop.current
        var isCancelled = currentThread.isCancelled
        while( !isCancelled && currentRunloop.run(mode: .default, before: Date.distantFuture) ) {
            isCancelled = currentThread.isCancelled
        }
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
